﻿using System.Reflection;

namespace Koala.Pro.Common
{
    public static class ReflectionHelper
    {
        public static bool IsAssignableToGenericType(Type givenType, Type genericType)
        {
            TypeInfo typeInfo = givenType.GetTypeInfo();
            if (typeInfo.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
            {
                return true;
            }
            Type[] interfaces = givenType.GetInterfaces();
            foreach (Type type in interfaces)
            {
                if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == genericType)
                {
                    return true;
                }
            }
            if (typeInfo.BaseType == null)
            {
                return false;
            }
            return IsAssignableToGenericType(typeInfo.BaseType, genericType);
        }

        public static List<object> GetAttributesOfMemberAndDeclaringType(MemberInfo memberInfo, bool inherit = true)
        {
            List<object> list = new List<object>();
            list.AddRange(memberInfo.GetCustomAttributes(inherit));
            if (memberInfo.DeclaringType != null)
            {
                list.AddRange(memberInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(inherit));
            }
            return list;
        }

        public static List<object> GetAttributesOfMemberAndType(MemberInfo memberInfo, Type type, bool inherit = true)
        {
            List<object> list = new List<object>();
            list.AddRange(memberInfo.GetCustomAttributes(inherit));
            list.AddRange(type.GetTypeInfo().GetCustomAttributes(inherit));
            return list;
        }

        public static List<TAttribute> GetAttributesOfMemberAndDeclaringType<TAttribute>(MemberInfo memberInfo, bool inherit = true) where TAttribute : Attribute
        {
            List<TAttribute> list = new List<TAttribute>();
            if (memberInfo.IsDefined(typeof(TAttribute), inherit))
            {
                list.AddRange(memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
            }
            if (memberInfo.DeclaringType != null && memberInfo.DeclaringType.GetTypeInfo().IsDefined(typeof(TAttribute), inherit))
            {
                list.AddRange(memberInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
            }
            return list;
        }

        public static List<TAttribute> GetAttributesOfMemberAndType<TAttribute>(MemberInfo memberInfo, Type type, bool inherit = true) where TAttribute : Attribute
        {
            List<TAttribute> list = new List<TAttribute>();
            if (memberInfo.IsDefined(typeof(TAttribute), inherit))
            {
                list.AddRange(memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
            }
            if (type.GetTypeInfo().IsDefined(typeof(TAttribute), inherit))
            {
                list.AddRange(type.GetTypeInfo().GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
            }
            return list;
        }

        public static TAttribute GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = null, bool inherit = true) where TAttribute : class
        {
            object obj = memberInfo.GetCustomAttributes(inherit: true).OfType<TAttribute>().FirstOrDefault();
            if (obj == null)
            {
                Type? reflectedType = memberInfo.ReflectedType;
                obj = (((object)reflectedType != null) ? reflectedType.GetTypeInfo().GetCustomAttributes(inherit: true).OfType<TAttribute>()
                    .FirstOrDefault() : null) ?? defaultValue;
            }
            return (TAttribute)obj;
        }

        public static TAttribute GetSingleAttributeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = null, bool inherit = true) where TAttribute : Attribute
        {
            if (memberInfo.IsDefined(typeof(TAttribute), inherit))
            {
                return memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().First();
            }
            return defaultValue;
        }

        internal static object GetPropertyByPath(object obj, Type objectType, string propertyPath)
        {
            object obj2 = obj;
            Type type = objectType;
            string fullName = type.FullName;
            string text = propertyPath;
            if (text.StartsWith(fullName))
            {
                text = text.Replace(fullName + ".", "");
            }
            string[] array = text.Split(new char[1] { '.' });
            foreach (string name in array)
            {
                obj2 = type.GetProperty(name);
                type = ((PropertyInfo)obj2).PropertyType;
            }
            return obj2;
        }

        internal static object GetValueByPath(object obj, Type objectType, string propertyPath)
        {
            object obj2 = obj;
            Type type = objectType;
            string fullName = type.FullName;
            string text = propertyPath;
            if (text.StartsWith(fullName))
            {
                text = text.Replace(fullName + ".", "");
            }
            string[] array = text.Split(new char[1] { '.' });
            foreach (string name in array)
            {
                PropertyInfo? property = type.GetProperty(name);
                obj2 = property.GetValue(obj2, null);
                type = property.PropertyType;
            }
            return obj2;
        }

        internal static void SetValueByPath(object obj, Type objectType, string propertyPath, object value)
        {
            Type type = objectType;
            string fullName = type.FullName;
            string text = propertyPath;
            if (text.StartsWith(fullName))
            {
                text = text.Replace(fullName + ".", "");
            }
            string[] array = text.Split(new char[1] { '.' });
            if (array.Length == 1)
            {
                objectType.GetProperty(array.First()).SetValue(obj, value);
                return;
            }
            for (int i = 0; i < array.Length - 1; i++)
            {
                PropertyInfo? property = type.GetProperty(array[i]);
                obj = property.GetValue(obj, null);
                type = property.PropertyType;
            }
            type.GetProperty(array.Last()).SetValue(obj, value);
        }

        internal static bool IsPropertyGetterSetterMethod(MethodInfo method, Type type)
        {
            if (!method.IsSpecialName)
            {
                return false;
            }
            if (method.Name.Length < 5)
            {
                return false;
            }
            return type.GetProperty(method.Name.Substring(4), BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic) != null;
        }
    }
}
